package com.atguigu.gmall.msg.listner;

import com.atguigu.gmall.common.utils.FormUtils;
import com.atguigu.gmall.common.utils.HttpUtils;
import com.atguigu.gmall.common.utils.RandomUtils;
import com.atguigu.gmall.msg.config.SmsProperties;
import com.atguigu.gmall.msg.consts.Keys;
import com.google.gson.Gson;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class MsgListner {
    String appCode;
    String host;
    String path;
    String method;
    String templateId;
    String smsSignId;

    @Autowired
    SmsProperties smsProperties;
    @Autowired
    StringRedisTemplate redisTemplate;

    @PostConstruct
    private void init() {
        this.appCode = smsProperties.getAppCode();
        this.host = smsProperties.getHost();
        this.path = smsProperties.getPath();
        this.method = smsProperties.getMethod();
        this.templateId = smsProperties.getTemplateId();
        this.smsSignId = smsProperties.getSmsSignId();
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("MSG_MESSAGE_QUEUE"),
            exchange = @Exchange(value = "UMS_USER_EXCHANGE", ignoreDeclarationExceptions = "true", type = ExchangeTypes.TOPIC),
            key = {"user.*"}
    ))
    public void sendMsg(String mobile, Channel channel, Message message) throws IOException {

        // 判断手机号是否正确
        if (!FormUtils.isMobile(mobile)) {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        // 验证手机号码发送短信的频率[第一次发送短信成功后再回来写频率校验]
        // 一分钟只能发送一次
        String mobileCodePerMinkey = Keys.CODE_PER_MIN_KEY + mobile;
        if (redisTemplate.hasKey(mobileCodePerMinkey)) {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        // 一天只能发送5次
        String mobileCodePerDayKey = Keys.CODE_PER_DAY_KEY + mobile;
        Object countObj = redisTemplate.opsForValue().get(mobileCodePerDayKey);
        if (countObj != null) {
            if (Integer.parseInt(countObj.toString()) >= 5) {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
        } else {
            redisTemplate.opsForValue().set(mobileCodePerDayKey, "0", 24, TimeUnit.HOURS);
        }

        // 生成验证码
        String code = RandomUtils.getFourBitRandom();

        //发送验证码
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 8e45699f00ff4bdbb807664045acd813
        headers.put("Authorization", "APPCODE " + appCode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("mobile", mobile);
        querys.put("param", "**code**:" + code + ",**minute**:" + Keys.CODE_EXPIRE_MINUTE);
        querys.put("smsSignId", smsSignId);
        querys.put("templateId", templateId);
        Map<String, String> bodys = new HashMap<String, String>();

        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            // 判断短信是否发送成功
            Gson gson = new Gson();
            Map map = gson.fromJson(result, Map.class);
            String resultCode = map.get("code").toString();
//            System.out.println(resultCode);
            if (!"0".equals(resultCode)) {
                // 短信发送失败
                if (message.getMessageProperties().getRedelivered()) {
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                } else {
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
                }
                return;
            }
            // 短信发送成功
            // 缓存验证码
            String mobileCodeKey = Keys.CODE_CODE_KEY + mobile;
            redisTemplate.opsForValue().set(mobileCodeKey, code, Keys.CODE_EXPIRE_MINUTE, TimeUnit.DAYS);
            // 更新用户获取验证码的频率
            redisTemplate.opsForValue().set(mobileCodePerMinkey, mobileCodePerMinkey, 1, TimeUnit.MINUTES);
            //更新手机号码今天获取验证码的次数
            redisTemplate.opsForValue().increment(mobileCodePerDayKey);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error(ExceptionUtils.getStackTrace(e));
            if (message.getMessageProperties().getRedelivered()) {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        }
    }
}
